package com.fiberhome.opticalbox.utils;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;

public class ImageUtil {

	public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;
		if (height > reqHeight || width > reqWidth) {
			final int heightRatio = Math.round((float) height / (float) reqHeight);
			final int widthRatio = Math.round((float) width / (float) reqWidth);
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}
		return inSampleSize;
	}

	public static Bitmap decodeResource(Resources res, int resId, int reqWidth, int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeResource(res, resId, options);
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeResource(res, resId, options);
	}

	public static Bitmap decodeStream(InputStream is, int reqWidth, int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(is, null, options);
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeStream(is, null, options);
	}

	public static Bitmap decodeByteArray(byte[] data, int offset, int length, int reqWidth, int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeByteArray(data, offset, length, options);
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeByteArray(data, offset, length, options);
	}

	public static Bitmap decodeFile(String pathName, int reqWidth, int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(pathName, options);
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(pathName, options);
	}

	/**
	 * 缩放为指定大小
	 */
	public static Bitmap decodeToSpecifySize(Bitmap bitmap, int reqWidth, int reqHeight) {
		int w = bitmap.getWidth();
		int h = bitmap.getHeight();
		Matrix matrix = new Matrix();
		float scaleWidth = (float) reqWidth / w;
		float scaleHeight = (float) reqHeight / h;
		matrix.postScale(scaleWidth, scaleHeight);
		return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
	}

	/**
	 * 缩放为指定比例
	 */
	public static Bitmap decodeToSpecifyRatio(Bitmap bitmap, int reqWidth, int reqHeight) {
		int w = bitmap.getWidth();
		int h = bitmap.getHeight();
		Matrix matrix = new Matrix();
		float scaleWidth = (float) reqWidth / w;
		float scaleHeight = (float) reqHeight / h;
		float scaleSize = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
		matrix.postScale(scaleSize, scaleSize);
		return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
	}

	/**
	 * 转换成圆角图片
	 */
	public static Bitmap roundedCornerImage(Bitmap resource, float roundSize) {
		final int color = 0xff424242;
		Bitmap output = Bitmap.createBitmap(resource.getWidth(), resource.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(output);
		canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, resource.getWidth(), resource.getHeight());
		final RectF rectF = new RectF(rect);

		paint.setAntiAlias(true);
		paint.setColor(color);
		canvas.drawARGB(0, 0, 0, 0);
		canvas.drawRoundRect(rectF, roundSize, roundSize, paint);

		paint.setXfermode(new android.graphics.PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(resource, 0, 0, paint);
		return output;
	}

	/**
	 * 转换成圆形图片
	 */
	public static Bitmap roundedImage(Bitmap resource) {
		final int color = 0xff424242;
		Bitmap output = Bitmap.createBitmap(resource.getWidth(), resource.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(output);
		canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, resource.getWidth(), resource.getHeight());
		final RectF rectF = new RectF(rect);

		paint.setAntiAlias(true);
		paint.setColor(color);
		canvas.drawARGB(0, 0, 0, 0);
		canvas.drawOval(rectF, paint);

		paint.setXfermode(new android.graphics.PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(resource, 0, 0, paint);
		return output;
	}

	/**
	 * 旋转图片
	 */
	public static Bitmap rotateImage(Bitmap resource, final int rotateDegree) {
		Matrix m = new Matrix();
		m.setRotate(rotateDegree, (float) resource.getWidth() / 2, (float) resource.getHeight() / 2);
		try {
			Bitmap bm1 = Bitmap.createBitmap(resource, 0, 0, resource.getWidth(), resource.getHeight(), m, true);
			return bm1;
		} catch (OutOfMemoryError ex) {
		}
		return null;
	}

	/**
	 * 质量压缩至300kb以下
	 */
	public static Bitmap compressImage(Bitmap resource) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		resource.compress(Bitmap.CompressFormat.JPEG, 100, baos);
		int options = 90; // 100
		while (baos.toByteArray().length / 1024 > 300) {
			baos.reset();
			options -= 10;
			resource.compress(Bitmap.CompressFormat.JPEG, options, baos);
		}
		ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
		return BitmapFactory.decodeStream(bais, null, null);
	}

	public static InputStream compressBitmap2InputStream(Bitmap resource) {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		resource.compress(Bitmap.CompressFormat.JPEG, 100, baos);
		int options = 90; // 100
		while (baos.toByteArray().length / 1024 > 512) {
			baos.reset();
			options -= 10;
			resource.compress(Bitmap.CompressFormat.JPEG, options, baos);
		}
		return new ByteArrayInputStream(baos.toByteArray());
	}

	public static Bitmap resizeBitmap(Bitmap input, int destWidth, int destHeight) {
		int srcWidth = input.getWidth();
		int srcHeight = input.getHeight();
		boolean needsResize = false;
		float p;
		if (srcWidth > destWidth || srcHeight > destHeight) {
			needsResize = true;
			if (srcWidth > srcHeight && srcWidth > destWidth) {
				p = (float) destWidth / (float) srcWidth;
				destHeight = (int) (srcHeight * p);
			} else {
				p = (float) destHeight / (float) srcHeight;
				destWidth = (int) (srcWidth * p);
			}
		} else {
			destWidth = srcWidth;
			destHeight = srcHeight;
		}
		if (needsResize) {
			Bitmap output = Bitmap.createScaledBitmap(input, destWidth, destHeight, true);
			return output;
		} else {
			return input;
		}
	}

	public static InputStream loadFromUri(Context context, String uri, int maxW, int maxH) throws IOException {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inScaled = false;
		options.inPreferredConfig = Bitmap.Config.RGB_565;
		BufferedInputStream stream = null;
		if (uri.startsWith(ContentResolver.SCHEME_CONTENT) || uri.startsWith(ContentResolver.SCHEME_FILE))
			stream = new BufferedInputStream(context.getContentResolver().openInputStream(Uri.parse(uri)), 16384);
		if (stream != null) {
			options.inSampleSize = computeSampleSize(stream, maxW, maxH);
			stream = null;
			stream = new BufferedInputStream(context.getContentResolver().openInputStream(Uri.parse(uri)), 16384);
		} else {
			return null;
		}
		return stream;
	}

	private static int computeSampleSize(InputStream stream, int maxW, int maxH) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(stream, null, options);
		double w = options.outWidth;
		double h = options.outHeight;
		int sampleSize = (int) Math.ceil(Math.max(w / maxW, h / maxH));
		return sampleSize;
	}
}
